/**
 IDEA Configurator
 Copyright (C) 2006 Justin Tomich<tomichj at gmail dot com>

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as
 published by the Free Software Foundation; either version 2 of the
 License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

package configurator;

import configurator.model.Module;
import configurator.model.ordered.*;

import org.w3c.dom.Document;

import java.io.File;
import javax.xml.parsers.ParserConfigurationException;


/**
 * Facade for building a module. Hides deep Module object tree. ModuleBuilder is
 * used by the ModuleConfiguratorTask to configure a Module instance.
 *
 * @author Justin Tomich
 */
public class ModuleBuilder
{
    private Module module;
    private boolean jdkSet;


    public ModuleBuilder(String moduleName, File rootDir, boolean relativePaths)
    {
        this.module = new Module(moduleName, rootDir, relativePaths);
    }


    public ModuleBuilder setExcludeOutputPaths(boolean excludeOutputPaths)
    {
        module.root().setExcludeOutputPaths(excludeOutputPaths);
        return this;
    }


    public ModuleBuilder setOutput(String path)
    {
        module.root().setOutput(path);
        return this;
    }


    public ModuleBuilder setOutputTest(String path)
    {
        module.root().setOutputTest(path);
        return this;
    }


    public ModuleBuilder addSources(String[] paths)
    {
        for (String path : paths)
        {
            addSource(path);
        }
        return this;
    }


    public ModuleBuilder addSource(String path)
    {
        module.root().content().addSource(path);
        return this;
    }


    public ModuleBuilder addTests(String[] paths)
    {
        for (String path : paths)
        {
            addTest(path);
        }
        return this;
    }


    public ModuleBuilder addTest(String path)
    {
        module.root().content().addTest(path);
        return this;
    }


    public ModuleBuilder addExcludes(String[] paths)
    {
        for (String path : paths)
        {
            addExclude(path);
        }
        return this;
    }


    public ModuleBuilder addExclude(String path)
    {
        module.root().content().addExclude(path);
        return this;
    }

    /////////////////////////////////////////////////////
    // orderEntry stuff below here
    //
    // default:
    //    inheritedJdk
    //    sourceFolder
    //    libraries
    // if inheritedJdk or sourceFolder is not specified, then use default order


    public ModuleBuilder addModuleDependency(String dependentModule,
                                             boolean exported)
    {
        module.root().add(new ModuleDependency(dependentModule, exported));
        return this;
    }


    public ModuleBuilder setInheritedJdk()
    {
        if (jdkSet) return this; // consider runtime instead
        jdkSet = true;
        module.root().add((new InheritedJdk()));
        return this;
    }


    public ModuleBuilder setModuleJdk(String jdkName)
    {
        if (jdkSet) return this; // consider runtime instead
        jdkSet = true;
        module.root().add((new ModuleJdk(jdkName)));
        return this;
    }


    public ModuleBuilder setSourceFolderEntry()
    {
        module.root().add(new SourceFolderEntry());
        return this;
    }


    public ModuleBuilder addClasspathFilter(String pattern)
    {
        module.root().addClasspathFilter(pattern);
        return this;
    }


    public ModuleBuilder addGlobalLibrary(String libraryName, boolean exported)
    {
        module.root().add(new GlobalLibrary(libraryName, exported));
        return this;
    }


    public ModuleBuilder addProjectLibrary(String libraryName, boolean exported)
    {
        module.root().add(new ProjectLibrary(libraryName, exported));
        return this;
    }


    public ModuleBuilder newModuleLibrary(String[] classes,
                                          String[] sources,
                                          String[] javadocs,
                                          String[] javadocUrls,
                                          boolean exported)
    {
        ModuleLibrary lib = new ModuleLibrary(exported);
        // assert classes != null; // do something like this??
        lib.addClasses(classes);
        lib.addSources(sources);
        lib.addJavadocs(javadocs);
        lib.addJavadocUrls(javadocUrls);
        module.root().add(lib);
        return this;
    }


    public ModuleBuilder newModuleLibraryClasses(String classes,
                                                 boolean exported)
    {
        ModuleLibrary lib = new ModuleLibrary(exported);
        lib.addClasses(classes);
        module.root().add(lib);
        return this;
    }


    public ModuleBuilder addModuleLibraryClasses(String originalClasses,
                                                 String additionalClasses)
    {
        ModuleLibrary lib = lib(originalClasses);
        lib.addClasses(additionalClasses);
        return this;
    }


    public ModuleBuilder addModuleLibraryJavadoc(String libraryClasses,
                                                 String javadocPath)
    {
        ModuleLibrary lib = lib(libraryClasses);
        lib.addJavadoc(javadocPath);
        return this;
    }


    public ModuleBuilder addModuleLibraryJavadocUrl(String libraryClasses,
                                                    String url)
    {
        ModuleLibrary lib = lib(libraryClasses);
        lib.addJavadocUrl(url);
        return this;
    }


    public ModuleBuilder addModuleLibrarySource(String libraryClasses,
                                                String sourcePath)
    {
        ModuleLibrary lib = lib(libraryClasses);
        lib.addSources(sourcePath);
        return this;
    }


    protected ModuleLibrary lib(String originalPath)
    {
        ModuleLibrary lib = module.root().get(originalPath);
        if (lib == null)
        {
            throw new RuntimeException("Could not find: " + originalPath);
        }
        return lib;
    }


    public Document toDom() throws ParserConfigurationException
    {
//        module.root().completeJdkAndSourceOrderEntries();
        return module.toDom();
    }


    public String toString()
    {
        return "ModuleBuilder{" +
               "module=" + module +
               "}";
    }
}
